﻿#ifndef IMAGEVIEW_H
#define IMAGEVIEW_H

#include "MeasureView_global.h"
#include <QMutex>
#include <QWidget>
#include <QSize>
#include <QSet>
#include <QSettings>
#include <QPen>

namespace Qly
{

const int DEFAULT_IMAGE_SIZE_X = 1920;
const int DEFAULT_IMAGE_SIZE_Y = 1200;

class ImageView;
//class LensManager;

class MEASUREVIEW_EXPORT Decoration
{
public:
    Decoration(ImageView * parent);
    void setEnable(bool ena = false);
    void setPen(const QPen &pen);
    void setColor(const QColor &cl);
    void setLineWidth(int lineWidth = 1);
    virtual void paint(QPainter &painter, int image_width, int image_height) = 0;
protected:
    bool m_enable;
    QPen m_pen;
    ImageView * m_pImageView;
};

class MEASUREVIEW_EXPORT Grid : public Decoration
{
    friend ImageView;
public:
    void setLineStyle(Qt::PenStyle style = Qt::DashDotLine);
    void setGridSize(int width = 100, int height = 100);
private:
    Grid(ImageView * parent);
    Q_DISABLE_COPY_MOVE(Grid)
    //Q_DISABLE_MOVE(Grid)
    void paint(QPainter &painter, int image_width, int image_height) override;
    int m_width = 100;
    int m_height = 100; 
};

class MEASUREVIEW_EXPORT CenterCross : public Decoration
{
    friend ImageView;
public:
    void setLineStyle(Qt::PenStyle style = Qt::SolidLine);
    void setCrossSize(int width = 30, int height = 30);
    void setRotate(double angle = 0.0);
private:
    CenterCross(ImageView * parent);
    Q_DISABLE_COPY_MOVE(CenterCross)
    //Q_DISABLE_MOVE(CenterCross)
    void paint(QPainter &painter, int image_width, int image_height) override;
    int m_width = 30;
    int m_height = 30;
    double m_angle = 0;
    QPen m_pen;
};

class MEASUREVIEW_EXPORT Ruler : public Decoration
{
    friend ImageView;
public:
    void setFont(const QFont &font);
    void setFontSize(int pointSize = 14);
    void setPosition(QPoint f); // 标尺的中心点在图像中的位置。以像素为单位。
    void setRuler(int length_pix, QString text); // 设置标尺的长度和上面显示的文字。
private:
    Ruler(ImageView * parent);
    Q_DISABLE_COPY_MOVE(Ruler)
    //Q_DISABLE_MOVE(Ruler)
    void paint( QPainter &painter, int image_width, int image_height ) override;
    int m_rulerOffsetX = 150; // 图像中标尺的位置
    int m_rulerOffsetY = 150; // 图像中标尺的位置
    int m_length_pix = 0;
    QString m_text;
    QFont m_font;
};

class MEASUREVIEW_EXPORT ImageView  : public QWidget
{
    Q_OBJECT
public:
    ImageView(QWidget *parent = nullptr, int defaultX = DEFAULT_IMAGE_SIZE_X, int defaultY = DEFAULT_IMAGE_SIZE_Y);
    double zoomFactor() {return m_zoomFactor;}
    void enableWheelZoom(bool on);
    /**
     * @brief addDocoration 在图上增加一个装饰，标尺、十字线等都属于装饰
     * @param pDeco
     */
    void addDocoration(Decoration * pDeco);

    /**
     * @brief removeDecoration 删除一个图上的装饰。
     * @param pDeco
     */
    void removeDecoration(Decoration *pDeco);

    /**
     * @brief removeAllDecoration 删除图上所有的装饰。这里不会删除中心十字线、网格和标尺。这三个对象是不可删除的。
     */
    void removeAllDecoration();

    QSize sizeHint() const Q_DECL_OVERRIDE;

    /**
     * @brief imageSize 返回图像尺寸
     * @return
     */
    QSize imageSize();
    /**
     * @brief image 获取图像。
     * @param decorate 是否在图像上画上网格线和中心十字。
     * @return
     */
    QImage image(bool decorate = false);

    /**
     * @brief setImage 更新图像。
     * @param image 新的图像。
     * @return 图像更新成功返回 true, 失败返回 false.
     */
    bool setImage(QImage &image);

    /**
     * @brief saveImage 将图像保存到文件中
     * @param fileName 带路径的完整文件名
     * @param decorate 图像中是否保留网格线和中心十字。
     * @return 保存成功返回 true, 失败返回 false.
     */
    bool saveImage(QString fileName, bool decorate = false);

    Grid & grid();
    CenterCross & centerCross();
    Ruler & ruler();

    /**
     * @brief setBrush 设置背景，当没有图像显示时，显示这个背景。
     * @param brush 一个特定的画刷。利用这个画刷可以在背景上显示一个图片或者特定颜色，也可以是渐变色等。
     */
    void setBrush(QBrush brush);
public slots:
    /**
     * @brief setZoomFactor 设置图像的缩放系数，[0.01, 10.0]
     * @param factor 图像的缩放系数，取值范围：[0.01, 10.0]。对应 1% - 1000%
     */
    void setZoomFactor(double factor);

    void setPixelSize(double oldPixelSize_um, double newPixelSize_um, int method);

    /**
     * @brief setLens 切换物镜。这时应该更新标尺，和更新各个测量图元
     * @param oldLensIndex 原先的物镜的 Index
     * @param newLensIndex 新的物镜的 Index
     */
//    void setLens(int oldLensIndex, int newLensIndex);
signals:
    /**
     * @brief 鼠标左键双击时输出鼠标在图像上的位置，考虑了图像的放缩。
     * @param point 以像素为单位的位置，是以中心点为原点。并且是在图像坐标系中的，不受图像缩放影响。
     */
    void mouseDoubleClicked(QPointF &point);

    /**
     * @brief mouseMoved 返回鼠标在图像上的位置，考虑了图像的放缩。
     * @param point 以像素为单位的位置，是以中心点为原点。并且是在图像坐标系中的，不受图像缩放影响。
     */
    void mouseMoved(const QPointF &point);

    /**
     * @brief zoomFactorChanged 图像的放缩系数改变时发出这个信号。通常是由于用户滚动了鼠标的滚轮导致图像缩放。
     * @param factor 缩放系数。
     */
    void zoomFactorChanged(double factor);
protected:
    void drawImage(QPainter &painter);
    void paintEvent(QPaintEvent *event)  Q_DECL_OVERRIDE;
    void mouseDoubleClickEvent(QMouseEvent *event)  Q_DECL_OVERRIDE;
    void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
    void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE;

protected:

//    LensManager * m_lensManager = nullptr;
    Grid m_grid;
    CenterCross m_cross;
    Ruler m_ruler;

    QSet<Decoration *> m_decoSet;
    QImage * m_pImage = nullptr;
    QSize m_size;
    QBrush m_brush;
    double m_zoomFactor = 1.0;
    bool m_bWheelZoom = true;

    double m_pixelSize_um = 1.0;
};


}
#endif // IMAGEVIEW_H
